import os
import re
import shutil
import zipfile
import tempfile
import time

import comtypes.client  # 修正comtypes导入
import xlrd
from docx2pdf import convert  # 用于将Word转换为PDF
import rarfile
import py7zr

# 生成zip文件的前缀
cl_prefix = '2425_37_13015_08092_'

# 论文所在文件夹
root_directory = 'D:\\恒星\\论文'

# 输出文件路径
output_path = 'D:\\恒星\\论文'

# 学生姓名和学号的映射文件
student_mapping_excel = (r"D:\\恒星\\论文\\mapping.xlsx")

# 需要提取文件的关键字
file_filter = '开题报告|任务书|中期报告'

change_to_pdf = False

rarfile.UNRAR_TOOL = r"C:\Program Files\WinRAR\UnRAR.exe"

# student_name_pattern = re.compile(r'.*-(\\s+):?([\u4e00-\u9fa5]+)')

student_name_pattern = re.compile(r'.*([\u4e00-\u9fa5]+)')
stu_name_mapping = dict()

def get_data_by_row(filename, start_rowx, end_rowx, start_colx, end_colx):
    result = []
    data = xlrd.open_workbook(filename)
    table = data.sheets()[0]
    if end_rowx == 0:
        end_rowx = table.nrows
    if end_colx == 0:
        end_colx = table.ncols
    for rowx in range(start_rowx, end_rowx):
        row = [str(table.cell_value(rowx, i)) for i in range(start_colx, end_colx) if str(table.cell_value(rowx, i)) != '']
        if len(row) > 0:
            # print(row)
            result.append(row)
    return result

def load_by_header():
    _num, _name = '', ''
    all_header = get_data_by_row(student_mapping_excel, 0, 1, 0, 0)
    for title in all_header:
        for i in range(len(title)):
            item = title[i]
            if item == '姓名':
                _name = i
            elif item == '学号':
                _num = i
    data = get_data_by_row(student_mapping_excel, 2, 0, 0, 0)
    for entry in data:
        num = entry[_num]
        name = entry[_name]
        stu_name_mapping[name] = num


def find_compressed_files(root_dir):
    """查找指定目录下所有zip, rar, 7z文件"""
    compressed_files = []
    for dirpath, _, filenames in os.walk(root_dir):
        for filename in filenames:
            if filename.lower().endswith(('.zip', '.rar', '.7z')):
                compressed_files.append(os.path.join(dirpath, filename))
    return compressed_files


def extract_compressed_file(file_path, extract_dir):
    """解压不同类型的压缩文件"""
    try:
        if file_path.lower().endswith('.zip'):
            with zipfile.ZipFile(file_path, 'r') as zip_ref:
                zip_ref.extractall(extract_dir)
        elif file_path.lower().endswith('.rar'):
            with rarfile.RarFile(file_path, 'r') as rar_ref:
                rar_ref.extractall(extract_dir)
        elif file_path.lower().endswith('.7z'):
            with py7zr.SevenZipFile(file_path, 'r') as sevenz_ref:
                sevenz_ref.extractall(extract_dir)
        print(f"成功解压: {file_path}")
        return True
    except Exception as e:
        print(f"解压失败 {file_path}: {str(e)}")
        return False

def find_target_pdf_files(root_dir):
    """查找包含开题报告、任务书、中期报告的Word文件，并提取学号信息"""
    target_files = []
    pattern = re.compile(file_filter, re.IGNORECASE)
    # 改进正则表达式，同时支持.doc和.docx
    for dirpath, _, filenames in os.walk(root_dir):
        for filename in filenames:
            if filename.lower().endswith('.pdf') and '论文终稿' in filename:
                # 尝试从文件名中提取学生姓名
                student_name_match = student_name_pattern.search(filename.split('-')[-1])
                if student_name_match:
                    student_name = student_name_match.group(0) if student_name_match else None
                    student_id = stu_name_mapping.get(student_name.strip())
                    if student_id:
                        # 添加文件格式信息
                        target_files.append({
                            'path': os.path.join(dirpath, filename),
                            'student_id': student_id,
                            'filename': filename,
                            'format': 'pdf'  # 新增格式信息
                        })
                    else:
                        print(f"警告: 文件 {filename} 中未找到匹配的学号信息，将被忽略")

    return target_files

def find_target_word_files(root_dir):
    """查找包含开题报告、任务书、中期报告的Word文件，并提取学号信息"""
    target_files = []
    pattern = re.compile(file_filter, re.IGNORECASE)
    # 改进正则表达式，同时支持.doc和.docx

    for dirpath, _, filenames in os.walk(root_dir):
        for filename in filenames:
            if filename.lower().endswith(('.docx', '.doc', 'pdf')) and pattern.search(filename):
                # 尝试从文件名中提取学生姓名
                student_name_match = student_name_pattern.search(filename.split('-')[-1])
                if student_name_match:
                    student_name = student_name_match.group(0) if student_name_match else None
                    student_id = stu_name_mapping.get(student_name.strip())
                    if student_id:
                        # 添加文件格式信息
                        if filename.lower().endswith('.docx'):
                            file_format = 'docx'
                        elif filename.lower().endswith('doc'):
                            file_format = 'doc'
                        elif filename.lower().endswith('pdf'):
                            file_format = 'pdf'
                        target_files.append({
                            'path': os.path.join(dirpath, filename),
                            'student_id': student_id,
                            'filename': filename,
                            'format': file_format  # 新增格式信息
                        })
                    else:
                        print(f"警告: 文件 {filename} 中未找到匹配的学号信息，将被忽略")

    return target_files


def convert_doc_to_pdf(doc_path, pdf_path):
    """将.doc文件转换为PDF（使用comtypes，适用于Windows系统）"""
    try:
        # 确保Word进程正确管理
        try:
            word = comtypes.client.GetActiveObject('Word.Application')
        except:
            word = comtypes.client.CreateObject('Word.Application')

        word.Visible = False  # 后台运行，不显示界面

        # 处理路径中的特殊字符
        doc_path = os.path.abspath(doc_path)
        pdf_path = os.path.abspath(pdf_path)

        doc = word.Documents.Open(doc_path)
        doc.SaveAs(pdf_path, FileFormat=17)  # 17是PDF格式的代码
        doc.Close()
        word.Quit()

        print(f"转换成功: {os.path.basename(doc_path)} -> {os.path.basename(pdf_path)}")
        return True
    except Exception as e:
        print(f"转换失败 {os.path.basename(doc_path)}: {str(e)}")
        return False


def convert_word_to_pdf(word_info, pdf_path):
    """根据文件格式选择合适的转换方法"""
    # 检查word_info是否为字典
    if not isinstance(word_info, dict):
        print(f"错误：word_info应为字典类型，实际为{type(word_info)}")
        return False

    try:
        if word_info['format'] == 'docx':
            convert(word_info['path'], pdf_path)
            print(f"转换成功: {os.path.basename(word_info['path'])} -> {os.path.basename(pdf_path)}")
            return True
        else:  # .doc格式
            return convert_doc_to_pdf(word_info['path'], pdf_path)
    except KeyError as e:
        print(f"错误：word_info缺少键{e}")
        return False
    except Exception as e:
        print(f"转换失败 {os.path.basename(word_info['path'])}: {str(e)}")
        return False


def create_student_zip_archives(student_files):
    """为每个学生创建单独的ZIP包"""
    os.makedirs(output_path, exist_ok=True)
    # 按学号分组文件
    student_groups = {}
    for file_info in student_files:
        if file_info['student_id'] not in student_groups:
            student_groups[file_info['student_id']] = []
        if 'pdf_path' in file_info:
            student_groups[file_info['student_id']].append(file_info['pdf_path'])
        else:
            student_groups[file_info['student_id']].append(file_info['path'])

            # 为每个学生创建ZIP包
    for student_id, files in student_groups.items():
        zip_filename = f"{cl_prefix}{student_id}_CL.zip"
        zip_filename = os.path.join(output_path, zip_filename)
        try:
            with zipfile.ZipFile(zip_filename, 'w', zipfile.ZIP_DEFLATED) as zipf:
                for file in files:
                    # 只存储文件名，不包含完整路径
                    zipf.write(file, os.path.basename(file))
            print(f"成功为学号 {student_id} 创建压缩文件: {zip_filename}")
        except Exception as e:
            print(f"为学号 {student_id} 创建压缩文件失败: {str(e)}")

    return len(student_groups)


def task():
    # 创建临时目录
    with tempfile.TemporaryDirectory() as temp_dir:
        extracted_dir = os.path.join(temp_dir, "extracted")
        pdf_dir = os.path.join(temp_dir, "pdfs")

        os.makedirs(extracted_dir, exist_ok=True)
        os.makedirs(pdf_dir, exist_ok=True)

        # 1. 查找所有压缩文件
        compressed_files = find_compressed_files(root_directory)
        print(f"找到 {len(compressed_files)} 个压缩文件")

        # 2. 解压所有压缩文件
        for file in compressed_files:
            extract_compressed_file(file, extracted_dir)

        # # 3. 查找目标Word文件并提取学号
        target_words = find_target_word_files(extracted_dir)
        print(f"找到 {len(target_words)} 个包含目标关键词和学号的Word文件")

        if not target_words:
            print("没有找到符合条件的Word文件，程序退出")
            return

        # # # 4. 转换为PDF并记录PDF路径
        if change_to_pdf:
            for word_file in target_words:
                pdf_name = os.path.splitext(word_file['filename'])[0] + ".pdf"
                pdf_path = os.path.join(pdf_dir, pdf_name)

                # 修复调用方式，传递word_file字典而不是路径字符串
                if convert_word_to_pdf(word_file, pdf_path):
                    word_file['pdf_path'] = pdf_path
                else:
                    word_file['pdf_path'] = None

            # 过滤掉转换失败的文件
            successful_conversions = [f for f in target_words if f.get('pdf_path') is not None]
            print(f"成功转换 {len(successful_conversions)} 个Word文件为PDF")

            if not successful_conversions:
                print("所有Word文件转换为PDF失败，程序退出")
                return

        # 5. 按学号创建单独的ZIP包
        student_count = create_student_zip_archives(target_words)
        print(f"已为 {student_count} 个学生创建了各自的ZIP包")

        # 提取论文
        target_pdfs = find_target_pdf_files(extracted_dir)
        for pdf_dict in target_pdfs:
            file_name = f"{cl_prefix}{pdf_dict.get('student_id')}_LW.pdf"
            shutil.copy(str(pdf_dict['path']), os.path.join(output_path, file_name))

    print("所有操作完成")


if __name__ == "__main__":
    try:
        start_t = time.time()
        load_by_header()
        print(f"成功加载 {len(stu_name_mapping)} 条学生信息")
        task()
        end_t = time.time()
        total_time = round(end_t - start_t, 2)
        print(f"运行时长--{total_time}秒")
    except Exception as e:
        print(f"程序运行出错: {str(e)}")
